package top.hzy520.stock.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.hzy520.common.constants.Constants;
import top.hzy520.common.exception.YuyuBuyException;
import top.hzy520.common.util.RedisUtils;
import top.hzy520.stock.dao.StockFlowMapper;
import top.hzy520.stock.dao.StockMapper;
import top.hzy520.stock.entity.ReduceStock;
import top.hzy520.stock.entity.Stock;
import top.hzy520.stock.entity.StockFlow;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: HouZeYu
 * @Description:
 * @Date: Created in 17:14 2018/6/8
 */
@Service
@Slf4j
public class StockServiceImpl implements StockService{
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StockMapper stockMapper;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private StockFlowMapper stockFlowMapper;
   /**
   *@Author: HouZeYu
   *@Description: 查询商品库存
   *@Date: 20:18 2018/6/8
   */
    @Override
    public int queryStock(Long skuId) {
        String stockKey=Constants.CACHE_GOODS_STOCK_KEY+":"+skuId;
        //查询缓存里面存取的该sku对应的库存
        Object object=redisTemplate.opsForValue().get(stockKey);
         Integer stockInRedis=Integer.valueOf(object.toString());
        return stockInRedis;
    }
     /**
     *@Author: HouZeYu
     *@Description: 初始化redis中的商品库存或者更新库存
     *@Date: 20:37 2018/6/8
     */
    @Override
    public void initStock(Long skuId) {
        String stockKey=Constants.CACHE_GOODS_STOCK_KEY+":"+skuId;
        String lockStockKey=Constants.CACHE_GOODS_LOCK_STOCK_KEY+":"+skuId;
        //查询数据库库存
        Stock stock= stockMapper.selectBySluId(skuId);
        //将数据库库存同步至redis中
     boolean reslut= redisUtils.initSkuStock(stockKey,lockStockKey,stock.getStock().toString(),stock.getLockStock().toString());
     if (reslut==false){
         throw new YuyuBuyException("初始化redis库存失败");
     }
    }
    /**
    *@Author: HouZeYu
    *@Description: 扣减该订单下所有商品库存
    *@Date: 8:20 2018/6/9
    */
    @Transactional
    @Override
    public Map<Long, Integer> reduceStock(List<ReduceStock> reduceStockList) {
        Long orderNo=reduceStockList.get(0).getOrderNo();
        //锁定订单防止该订单二次提交
        boolean lockResult=redisUtils.lockOrder(Constants.LOCK_ORDER+orderNo.toString(),orderNo.toString(),300000);
         if (!lockResult){
             //锁定失败表示订单已经提交
             return Collections.EMPTY_MAP;
         }
         Map<Long,Integer> map=new HashMap<>();
        //依次对订单内每个商品进行库存的扣减
        reduceStockList.stream().forEach(
                param->{
                    String stockKey=Constants.CACHE_GOODS_STOCK_KEY+":"+param.getSkuId();
                    String stockLockKey=Constants.CACHE_GOODS_LOCK_STOCK_KEY+":"+param.getSkuId();
                    //扣减redis库存
             Object result=redisUtils.reduceLock(stockKey,stockLockKey,param.getReduceCount().toString(),String.valueOf(Math.abs(param.getReduceCount())));
                   //判断是否扣减成功
                    if (result instanceof Long){
                     // 库存不足或者没库存返回-1
                        map.put(param.getSkuId(),-1);
                    }else if (result instanceof List){
                        //库存扣减成功则插入数据库库存流水账
                      List resultList= (List) result;
                    int  stockChangeAfter=((Long)resultList.get(0)).intValue();
                    int  stockLockChangeAfter=((Long)resultList.get(1)).intValue();
                        //插入库存流水
                        StockFlow stockFlow=new StockFlow();
                        stockFlow.setOrderNo(orderNo);
                        stockFlow.setSkuId(param.getSkuId());
                        stockFlow.setStockBefore(stockChangeAfter+Math.abs(param.getReduceCount()));
                        stockFlow.setStockChange(Math.abs(param.getReduceCount()));
                        stockFlow.setStockAfter(stockChangeAfter);
                        stockFlow.setLockStockBefore(stockLockChangeAfter+param.getReduceCount());
                        stockFlow.setLockStockChange(Math.abs(param.getReduceCount()));
                        stockFlow.setLockStockAfter(stockLockChangeAfter);
                        stockFlowMapper.insertSelective(stockFlow);
                        map.put(param.getSkuId(),1);
                    }
                }
        );
        return map;
    }
}
